// CommonUtils.RsaUtil
using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;

namespace CommonUtils
{
	public static class RsaUtil
	{
		public static RSACryptoServiceProvider LoadPublicKey(string publicKeyPem)
		{
			try
			{
				publicKeyPem = publicKeyPem.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "").Replace("\r", "")
					.Replace("\n", "");
				string publicKeyXml = RSAPublicKeyJava2DotNet(publicKeyPem);
				RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
				publicRsa.FromXmlString(publicKeyXml);
				return publicRsa;
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		private static string RSAPublicKeyJava2DotNet(string publicKey)
		{
			RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
			return $"<RSAKeyValue><Modulus>{Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned())}</Modulus><Exponent>{Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned())}</Exponent></RSAKeyValue>";
		}

		public static RSACryptoServiceProvider LoadPrivateKeyPKCS1(string privateKeyPemPkcs1, string signType)
		{
			try
			{
				privateKeyPemPkcs1 = privateKeyPemPkcs1.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("\r", "")
					.Replace("\n", "");
				byte[] data = null;
				data = Convert.FromBase64String(privateKeyPemPkcs1);
				return DecodeRSAPrivateKey(data, signType);
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey, string signType)
		{
			MemoryStream mem = new MemoryStream(privkey);
			BinaryReader binr = new BinaryReader(mem);
			byte bt = 0;
			ushort twobytes = 0;
			int elems = 0;
			try
			{
				switch (binr.ReadUInt16())
				{
					case 33072:
						binr.ReadByte();
						break;
					case 33328:
						binr.ReadInt16();
						break;
					default:
						return null;
				}
				twobytes = binr.ReadUInt16();
				if (twobytes != 258)
				{
					return null;
				}
				if (binr.ReadByte() != 0)
				{
					return null;
				}
				elems = GetIntegerSize(binr);
				byte[] MODULUS = binr.ReadBytes(elems);
				elems = GetIntegerSize(binr);
				byte[] E = binr.ReadBytes(elems);
				elems = GetIntegerSize(binr);
				byte[] D = binr.ReadBytes(elems);
				elems = GetIntegerSize(binr);
				byte[] P = binr.ReadBytes(elems);
				elems = GetIntegerSize(binr);
				byte[] Q = binr.ReadBytes(elems);
				elems = GetIntegerSize(binr);
				byte[] DP = binr.ReadBytes(elems);
				elems = GetIntegerSize(binr);
				byte[] DQ = binr.ReadBytes(elems);
				elems = GetIntegerSize(binr);
				byte[] IQ = binr.ReadBytes(elems);
				CspParameters CspParameters = new CspParameters();
				CspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
				int bitLen = 1024;
				if ("RSA2".Equals(signType))
				{
					bitLen = 2048;
				}
				RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(bitLen, CspParameters);
				RSAParameters RSAparams = default(RSAParameters);
				RSAparams.Modulus = MODULUS;
				RSAparams.Exponent = E;
				RSAparams.D = D;
				RSAparams.P = P;
				RSAparams.Q = Q;
				RSAparams.DP = DP;
				RSAparams.DQ = DQ;
				RSAparams.InverseQ = IQ;
				RSA.ImportParameters(RSAparams);
				return RSA;
			}
			catch (Exception ex)
			{
				throw ex;
			}
			finally
			{
				binr.Close();
			}
		}

		private static int GetIntegerSize(BinaryReader binr)
		{
			byte bt = 0;
			byte lowbyte = 0;
			byte highbyte = 0;
			int count = 0;
			bt = binr.ReadByte();
			if (bt != 2)
			{
				return 0;
			}
			bt = binr.ReadByte();
			switch (bt)
			{
				case 129:
					count = binr.ReadByte();
					break;
				case 130:
					{
						highbyte = binr.ReadByte();
						lowbyte = binr.ReadByte();
						byte[] modint = new byte[4] { lowbyte, highbyte, 0, 0 };
						count = BitConverter.ToInt32(modint, 0);
						break;
					}
				default:
					count = bt;
					break;
			}
			while (binr.ReadByte() == 0)
			{
				count--;
			}
			binr.BaseStream.Seek(-1L, SeekOrigin.Current);
			return count;
		}

		public static RSACryptoServiceProvider LoadPrivateKeyPKCS8(string privateKeyPemPkcs8)
		{
			try
			{
				privateKeyPemPkcs8 = privateKeyPemPkcs8.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("\r", "")
					.Replace("\n", "");
				string privateKeyXml = RSAPrivateKeyJava2DotNet(privateKeyPemPkcs8);
				RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
				publicRsa.FromXmlString(privateKeyXml);
				return publicRsa;
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		public static string RSAPrivateKeyJava2DotNet(string privateKeyPemPkcs8)
		{
			RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKeyPemPkcs8));
			return $"<RSAKeyValue><Modulus>{Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned())}</Modulus><Exponent>{Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned())}</Exponent><P>{Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned())}</P><Q>{Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned())}</Q><DP>{Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned())}</DP><DQ>{Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned())}</DQ><InverseQ>{Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned())}</InverseQ><D>{Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned())}</D></RSAKeyValue>";
		}

		public static RSACryptoServiceProvider LoadPrivateKey(string privateKeyStr, string keyFormat, string signType)
		{
			if (keyFormat == "PKCS1")
			{
				return LoadPrivateKeyPKCS1(privateKeyStr, signType);
			}
			return LoadPrivateKeyPKCS8(privateKeyStr);
		}

		public static RSACryptoServiceProvider LoadPrivateKey(string privateKeyStr, string keyFormat)
		{
			if (keyFormat == "PKCS1")
			{
				return LoadPrivateKeyPKCS1(privateKeyStr);
			}
			return LoadPrivateKeyPKCS8(privateKeyStr);
		}

		public static RSACryptoServiceProvider LoadPrivateKeyPKCS1(string privateKeyPemPkcs1)
		{
			try
			{
				privateKeyPemPkcs1 = privateKeyPemPkcs1.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("\r", "")
					.Replace("\n", "");
				string signType = "RSA";
				if (privateKeyPemPkcs1.Length > 1200)
				{
					signType = "RSA2";
				}
				byte[] data = null;
				data = Convert.FromBase64String(privateKeyPemPkcs1);
				return DecodeRSAPrivateKey(data, signType);
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		public static RSACryptoServiceProvider LoadPublicCert(string publicKeyCert)
		{
			try
			{
				publicKeyCert = publicKeyCert.Replace("-----BEGIN CERTIFICATE-----", "").Replace("-----END CERTIFICATE-----", "").Replace("\r", "")
					.Replace("\n", "");
				byte[] bytesCerContent = Convert.FromBase64String(publicKeyCert);
				X509Certificate2 x509 = new X509Certificate2(bytesCerContent);
				return (RSACryptoServiceProvider)x509.PublicKey.Key;
			}
			catch (Exception)
			{
				return null;
			}
		}

		public static X509Certificate2 LoadPublicCert2(string publicKeyCert)
		{
			try
			{
				publicKeyCert = publicKeyCert.Replace("-----BEGIN CERTIFICATE-----", "").Replace("-----END CERTIFICATE-----", "").Replace("\r", "")
					.Replace("\n", "");
				byte[] bytesCerContent = Convert.FromBase64String(publicKeyCert);
				return new X509Certificate2(bytesCerContent);
			}
			catch (Exception)
			{
				return null;
			}
		}
	}
}
